package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.*;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.service.WmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.itheima.wemedia.vo.WmNewsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @description <p>自媒体图文内容信息 业务实现</p>
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private KafkaTemplate kafkaTemplate;


    /**
     * 分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<WmNews> pageResult(WmNewsPageReqDto dto) {

        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> lqw = Wrappers.<WmNews>lambdaQuery()
                .eq(WmNews::getUserId, RequestContextUtil.getUserId())
                .eq(dto.getStatus() != null, WmNews::getStatus, dto.getStatus())
                .like(!StringUtils.isEmpty(dto.getKeyword()), WmNews::getTitle, dto.getKeyword())
                .eq(dto.getChannelId() != null, WmNews::getChannelId, dto.getChannelId())
                .ge(dto.getBeginPubDate() != null, WmNews::getPublishTime, dto.getBeginPubDate())
                .le(dto.getEndPubDate() != null, WmNews::getPublishTime, dto.getEndPubDate());
        //执行查询
        page(page, lqw);

        //构建返回结果
        return PageResultVo.pageResult(dto.getPage(), dto.getSize(), page.getTotal(), page.getRecords());
    }

    /**
     * 文章删除
     *
     * @param newsId
     */
    @Override
    @Transactional
    public void deleteById(int newsId) {
        WmNews wmNews = getById(newsId);
        if (wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED
                || wmNews.getEnable() == BusinessConstants.WmNewsConstants.ENABLE_ON) {
            throw new LeadNewsException("文章已发布/上架，删除失败");
        }
        //删除文章
        removeById(newsId);
        //删除文章与素材关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, newsId));
    }


    /**
     * 文章上架与下架处理
     *
     * @param paramMap
     */
    /**
     * 文章上下架处理
     *
     * @param dto
     */
    @Override
    public void downOrUp(DownOrUpDto dto) {
        //1. 通过id查询
        WmNews wmNews = query().eq("id", dto.getId()).eq("user_id", RequestContextUtil.getUserId()).one();
        if(null == wmNews){
            // 防止 不正常操作。直接用postman
            throw new LeadNewsException("所查询的文章不存在!");
        }
        //2. 判断状态是否为9，不为9就报错
        if(wmNews.getStatus() != BusinessConstants.WmNewsConstants.STATUS_PUBLISHED){
            throw new LeadNewsException("文章状态不为已发布，不能上架或下架!");
        }
        WmNews updatePojo = new WmNews();
        updatePojo.setId(dto.getId());
        if (dto.getEnable()== BusinessConstants.WmNewsConstants.ENABLE_OFF) {
            //3.1 下架，更新enable值，还更新status=0
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);
        }
        //3.2 更新enable的值
        updatePojo.setEnable(dto.getEnable());
        updateById(updatePojo);
        // 同步文章微服上下架处理
        dto.setId(wmNews.getArticleId());

        kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_DOWN_OR_UP_TOPIC, JSON.toJSONString(dto));
    }


    /**
     * 发布文章
     *
     * @param draft
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public void submit(Boolean draft, WmNewsDtoSave dto) {
        LocalDateTime now = LocalDateTime.now();
        //添加文章信息到数据库
        WmNews pojo = new WmNews();
        //把前端数据拷贝
        BeanUtils.copyProperties(dto, pojo);
        //如果没有选择时间，填充当前时间
        if(pojo==null){
            pojo.setSubmitedTime(now);
        }
        //设置属性值
        pojo.setUserId(Long.valueOf(RequestContextUtil.getUserId()));
        //提交时间设置
        if (null == dto.getPublishTime()) {
            pojo.setSubmitedTime(now);
        }
        if (!draft) {
            //提交审核
            pojo.setSubmitedTime(now);
        }
        pojo.setStatus(draft ? 0 : 1);
        //封面图片如果有值，则用逗号分割
        if (!CollectionUtils.isEmpty(dto.getImages())) {
            String imageStr = String.join(",", dto.getImages());
            pojo.setImages(imageStr);
        }
        //behaviour.com.itheima.search.pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);

        //自动设置封面图片
        setWmNewsType(dto, pojo);

        //保存还是存草稿
        if (null == dto.getId()) {
            save(pojo);
            pojo.setCreatedTime(now);
        } else {
            updateById(pojo);
            //删除旧的文章素材关系
            removeWmNewsMaterialRelationship(pojo.getId());
        }

        //添加文章素材关系
        addWmNewsMaterialRelationship(pojo);

        // 文章自动审核处理
        if (pojo.getStatus() == BusinessConstants.WmNewsConstants.STATUS_SUBMIT) {
            //如果是提交待审核的，则发消息给kafka,消息内容为文章的id
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC, pojo.getId().toString());
        }
    }

    // 文章发布--添加文章素材关系
    private void addWmNewsMaterialRelationship(WmNews pojo) {
        //存储内容图片，封面图片
        HashSet<String> pics = new HashSet<>();
        //封面图片
        List<String> coverList = new ArrayList<>();
        if (!StringUtils.isEmpty(pojo.getImages())) {
            //获取封面的图片
            String[] coverArr = pojo.getImages().split(",");

            //去除封面图片前缀，
            coverList = Arrays.stream(coverArr).map(this::removePrefix).collect(Collectors.toList());
            pics.addAll(coverList);
        }
        //处理内容图片
        // 获取内容处理
        String content = pojo.getContent();
        ArrayList<String> contentImageList = new ArrayList<>();
        if (!StringUtils.isEmpty(content)) {
            //内容转换格式
            List<WmNewsContentNodeDto> contentList = JSON.parseArray(content, WmNewsContentNodeDto.class);
            //过滤留下图片
            contentList.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                    .map(WmNewsContentNodeDto::getValue)
                    .map(this::removePrefix)
                    .collect(Collectors.toList());
            pics.addAll(contentImageList);
        }
        //通过图片查询素材表得到素材的id
        //url相同
        LambdaQueryWrapper<WmMaterial> lqw = Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, pics);
        List<WmMaterial> wmMaterialList = wmMaterialMapper.selectList(lqw);
        Map<String, Long> materialMap = wmMaterialList.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        //封面的图片
        addNewsMaterialRelationship(pojo.getId(), coverList, materialMap, BusinessConstants.WmNewsConstants.WM_COVER_REFERENCE);

        //内容的图片
        addNewsMaterialRelationship(pojo.getId(), contentImageList, materialMap, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);

    }

    //文章发布--添加文章素材关系--封面的图片/内容的图片
    private void addNewsMaterialRelationship(Long id, List<String> coverList, Map<String, Long> materialMap, int type) {
        for (int i = 0; i < coverList.size(); i++) {
            WmNewsMaterial nm = new WmNewsMaterial();
            //设置属性
            nm.setType(type);
            nm.setOrd(i + 1);
            nm.setNewsId(id);
            //通过图片的url找素材的id
            Long materialId = materialMap.get(coverList.get(i));
            nm.setMaterialId(materialId);
            //保存
            wmNewsMaterialMapper.insert(nm);
        }
    }

    // 文章发布--删除旧的文章素材关系
    private void removeWmNewsMaterialRelationship(Long id) {
        wmNewsMaterialMapper.deleteByMap(
                Collections.singletonMap("news_id", id)
        );

       /*方式二 LambdaQueryWrapper<WmNewsMaterial> queryWrapper = Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId, id);
        wmNewsMaterialMapper.delete(queryWrapper);*/
    }

    //文章发布--自动设置封面图片
    private void setWmNewsType(WmNewsDtoSave dto, WmNews pojo) {
        //获取type的值,-1=自动
        if (dto.getType() == -1) {
            //获取文章内容
            String content = dto.getContent();
            if (!StringUtils.isEmpty(content)) {
                List<WmNewsContentNodeDto> contentList = JSON.parseArray(content, WmNewsContentNodeDto.class);
                //获取图片
                List<String> imageList = contentList.stream()
                        .filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                        .map(WmNewsContentNodeDto::getValue)
                        .collect(Collectors.toList());
                //根据图片数量设置type值跟封面
                int count = imageList.size();
                //无图，没有封面
                if (count == 0) {
                    pojo.setImages("");
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                } else if (count < 3) {
                    //图片小于3张，取第一个做封面
                    pojo.setImages(imageList.get(0));
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
                } else {
                    //图片大于三张，取前三张做图片
                    pojo.setImages(imageList.stream().limit(3).collect(Collectors.joining(",")));
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);
                }
            } else {
                pojo.setImages("");
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
            }
        }
    }

    //文章发布--正则表达式处理路径
    private String removePrefix(String url) {
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }

    /**
     * 文章列表 分页查询 给后台管理人员，人工审核
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo findPage4Admin(WmNewsPageReqDto dto) {
        //1. 设置分页参数
        Page<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //2. 构建查询条件
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus());
        lqw.like(!StringUtils.isEmpty(dto.getTitle()), WmNews::getTitle, dto.getTitle());
        //3. 查询
        page(pageInfo, lqw);
        //4. 获取查询的结果集
        List<WmNews> wmNewsList = pageInfo.getRecords();
        //5. 提取结果集中的用户id
        List<WmNewsVo> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(wmNewsList)) {
            List<Long> userIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //6. 通过用户id查询用户信息
            // key=用户id, value=用信息对象
            Map<Integer, WmUser> userInfoMap = getUserInfoByIds(userIds);
            //7. WmNews转成WmNewsVo(authorName)
            voList = wmNewsList.stream().map(wmNews -> WmNewsVo.build(wmNews, userInfoMap.get(wmNews.getUserId()))).collect(Collectors.toList());
        }
        //8. 构建分布结果返回
        return PageResultVo.pageResult(dto.getPage(), dto.getSize(), pageInfo.getTotal(), voList);
    }

    /**
     * 通过用户id集合批量查询用户信息
     *
     * @param userIds
     * @return map<key = 用户id, value = WmUser对象>
     */
    private Map<Integer, WmUser> getUserInfoByIds(List<Long> userIds) {
        // <forEach> in (id,id,id), userIds.size=0 会报错的
        // select * from wm_user where id in ()     会报错的
        Map<Integer, WmUser> result = new HashMap<>();
        if (!CollectionUtils.isEmpty(userIds)) {
            List<WmUser> wmUsers = wmUserMapper.selectBatchIds(userIds);
            result = wmUsers.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));
            //wmUsers.stream().collect(Collectors.toMap(WmUser::getId, u->u));
        }
        return result;
    }


    /**
     * 人工审核 - 通过
     *
     * @param dto
     */
    @Override
    public void authPass(AuthReqDto dto) {
        WmNews updatePojo = new WmNews();
        updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
        updatePojo.setId(dto.getId());
        updateById(updatePojo);
    }

    /**
     * 人工审核 - 驳回
     *
     * @param dto
     */
    @Override
    public void authFail(AuthReqDto dto) {
        WmNews updatePojo = new WmNews();
        updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
        updatePojo.setReason(dto.getMsg());
        updatePojo.setId(dto.getId());
        updateById(updatePojo);
    }

    /**
     * 查看文章详情
     *
     * @param wmNewsId
     * @return
     */
    @Override
    public WmNewsVo getOneVo(Long wmNewsId) {
        WmNews wmNews = getById(wmNewsId);
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        WmNewsVo vo = WmNewsVo.build(wmNews, wmUser);
        return vo;
    }

    /**
     *查询需要同步的文章
     * @param dto
     * @return
     */
    @Override
    public List<WmNewsVo> list4ArticleSync(WmNewsPageReqDto dto) {
        //1. 构建条件status=4/8
        //2. 查询，得到数据列表
        List<WmNews> wmNewsList = query()
                .in("status", dto.getStatus())
                .le(null != dto.getEndPubDate(), "publish_time", dto.getEndPubDate()).list();
        //3. 获取所有作者wm_user_id
        List<WmNewsVo> voList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(wmNewsList)){
            // 自媒体账号id
            List<Long> wmUserIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //4. 批量查询wm_user表(ap_user_id作者id, name=作者名称)
            List<WmUser> wmUserList = wmUserMapper.selectBatchIds(wmUserIds);
            // map<userId,WmUser>
            Map<Integer, WmUser> wmUserInfoMap = wmUserList.stream()
                    .collect(Collectors.toMap(WmUser::getId, Function.identity()));
            //5. 转成wmNewsVo
            voList = wmNewsList.stream().map(wmNews -> WmNewsVo
                    .build(wmNews, wmUserInfoMap.get(wmNews.getUserId())))
                    .collect(Collectors.toList());
        }
        //6. 返回
        return voList;
    }
}

















